package base.ctrl;

import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.render.JsonRender;

import base.jfinal.JsonUtil;
import base.jfinal.plugin.ReadSql;
import base.model.SessionModel;

/**
 * 基础Controller
 */
public abstract class BaseController extends Controller {

    public Logger log = Logger.getLogger(getClass());
    private boolean parseJson = false;
    private Map<String, Object> jsonData;

    public SessionModel GetSM() {
        if (getRequest().getSession() != null) {
            return (SessionModel) getRequest().getSession().getAttribute("SessionModel");
        } else {
            throw new RuntimeException("登录超时！");
        }
    }

    /*
     * 通过sqlKey查询sql语句，并查询出结果，返回List<Record> strSqlKey格式 如：emp.empList
     * emp为文件名;empList为emp文件里的一个sql语句的Key值
     */
    public Record getDBRecord(String strSqlKey, Map<String, Object> map) {
        Record record = new Record();
        // 取得sql
        String strSql = ReadSql.getSql(strSqlKey);

        // 使用velocity模板，实例化velocity上下文
        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }
        StringWriter result = new StringWriter();
        try {
            Velocity.evaluate(context, result, "report" + strSqlKey, strSql);
            record = Db.findFirst(result.toString());
        } catch (Exception e) {
            log.error("数据查询失败：sqlKey" + strSqlKey + ",错误内容：" + e.getMessage());
            throw new RuntimeException("数据查询失败");
        }
        return record;
    }

    public String getSql(String strSqlKey, Map<String, Object> map) {
        String strSql = ReadSql.getSql(strSqlKey);
        // 使用velocity模板，实例化velocity上下文
        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }
        StringWriter result = new StringWriter();
        try {
            Velocity.evaluate(context, result, "report" + strSqlKey, strSql);
            return result.toString();
        } catch (Exception e) {
            log.error("数据查询失败：sqlKey" + strSqlKey + ",错误内容：" + e.getMessage());
            throw new RuntimeException("数据查询失败");
        }
    }

    /*
     * 通过sqlKey查询sql语句，并查询出结果，返回List<Record> strSqlKey格式 如：emp.empList
     * emp为文件名;empList为emp文件里的一个sql语句的Key值
     */
    public List<Record> getDBList(String strSqlKey, Map<String, Object> map) {
        List<Record> list = new ArrayList<Record>();
        // 取得sql
        String strSql = ReadSql.getSql(strSqlKey);

        // 使用velocity模板，实例化velocity上下文
        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }

        StringWriter result = new StringWriter();
        try {
            Velocity.evaluate(context, result, "report" + strSqlKey, strSql);
            list = Db.find(result.toString());
        } catch (Exception e) {
            log.error("数据查询失败：sqlKey" + strSqlKey + ",错误内容：" + e.getMessage());
            throw new RuntimeException("数据查询失败");
        }
        return list;
    }

    public String getDBRecordToJson(String strSqlKey, Map<String, Object> map) {
        Record record = new Record();
        // 取得sql
        String strSql = ReadSql.getSql(strSqlKey);

        // 使用velocity模板，实例化velocity上下文
        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }

        StringWriter result = new StringWriter();
        try {
            Velocity.evaluate(context, result, "report" + strSqlKey, strSql);
            record = Db.findFirst(result.toString());
        } catch (Exception e) {
            log.error("数据查询失败：sqlKey" + strSqlKey + ",错误内容：" + e.getMessage());
            throw new RuntimeException("数据查询失败");
        }
        return record.toJson();
    }

    public String getDBListToJson(String strSqlKey, Map<String, Object> map) {
        List<Record> lst = new ArrayList<Record>();
        // 取得sql
        String strSql = ReadSql.getSql(strSqlKey);

        // 使用velocity模板，实例化velocity上下文
        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }
        StringWriter result = new StringWriter();
        try {
            Velocity.evaluate(context, result, "report" + strSqlKey, strSql);
            lst = Db.find(result.toString());
        } catch (Exception e) {
            log.error("数据查询失败：sqlKey" + strSqlKey + ",错误内容：" + e.getMessage());
            throw new RuntimeException("数据查询失败");
        }
        return (new JsonUtil(lst)).toString();
    }

    protected void rendJson(Object json) {
        String agent = getRequest().getHeader("User-Agent");
        if (agent.contains("MSIE"))
            this.render(new JsonRender(json).forIE());
        else {
            this.render(new JsonRender(json));
        }
    }

    public String getPara(String name) {
        parseJson();
        String value = null;
        if (jsonData != null) {
            if (jsonData.get(name.toLowerCase()) != null
                    && StrKit.notBlank(jsonData.get(name.toLowerCase()).toString())) {
                value = jsonData.get(name.toLowerCase()).toString();
            }
        } else {
            value = this.getRequest().getParameter(name);
        }
        return value;
    }

    public String getPara(String name, String defaultValue) {
        String value = getPara(name);
        return StrKit.notBlank(value) ? value : defaultValue;
    }

    public Integer getParaToInt(String name) {
        String value = getPara(name);
        if (value.startsWith("N") || value.startsWith("n"))
            return -Integer.parseInt(value.substring(1));
        return Integer.parseInt(value);
    }

    public Integer getParaToInt(String name, Integer defaultValue) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return defaultValue;
        if (value.startsWith("N") || value.startsWith("n"))
            return -Integer.parseInt(value.substring(1));
        return Integer.parseInt(value);
    }

    public Boolean getParaToBoolean(String name) {
        String value = getPara(name);
        if ("1".equals(value) || "true".equals(value))
            return Boolean.TRUE;
        else if ("0".equals(value) || "false".equals(value))
            return Boolean.FALSE;
        throw new RuntimeException("Can not parse the parameter \"" + value + "\" to boolean value.");
    }

    public Boolean getParaToBoolean(String name, Boolean defaultValue) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return defaultValue;
        value = value.trim().toLowerCase();
        if ("1".equals(value) || "true".equals(value))
            return Boolean.TRUE;
        else if ("0".equals(value) || "false".equals(value))
            return Boolean.FALSE;
        throw new RuntimeException("Can not parse the parameter \"" + value + "\" to boolean value.");
    }

    public Long getParaToLong(String name) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return null;
        if (value.startsWith("N") || value.startsWith("n"))
            return -Long.parseLong(value.substring(1));
        return Long.parseLong(value);
    }

    public Long getParaToLong(String name, Long defaultValue) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return defaultValue;
        if (value.startsWith("N") || value.startsWith("n"))
            return -Long.parseLong(value.substring(1));
        return Long.parseLong(value);
    }

    public Float getParaToFloat(String name) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return null;
        return Float.parseFloat(value);
    }

    public Float getParaToFloat(String name, Float defaultValue) {
        String value = getPara(name);
        if (StrKit.isBlank(value))
            return defaultValue;
        return Float.parseFloat(value);
    }

    public JSONArray getParaToArr(String name) {
        parseJson();
        if (jsonData != null) {
            Object obj = jsonData.get(name.toLowerCase());
            if (obj instanceof JSONArray) {
                return (JSONArray) obj;
            }
        }
        return null;
    }

    public List<Map<String, Object>> getParaToList(String name) {
        parseJson();
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        if (jsonData != null) {
            Object obj = jsonData.get(name.toLowerCase());
            if (obj instanceof JSONArray) {
                JSONArray jsonArr = (JSONArray) obj;
                Iterator<Object> it = jsonArr.iterator();
                while (it.hasNext()) {
                    JSONObject json = (JSONObject) it.next();
                    Map<String, Object> jsonMap = new HashMap<String, Object>();
                    for (Object k : json.keySet()) {
                        Object v = json.get(k);
                        jsonMap.put(k.toString().toLowerCase(), v);
                    }
                    list.add(jsonMap);
                }
                return list;
            }
            return list;
        } else {
            String value = this.getRequest().getParameter(name);
            JSONArray jsonArr = JSON.parseArray(value);
            Iterator<Object> it = jsonArr.iterator();
            while (it.hasNext()) {
                JSONObject json = (JSONObject) it.next();
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                for (Object k : json.keySet()) {
                    Object v = json.get(k);
                    jsonMap.put(k.toString().toLowerCase(), v);
                }
                list.add(jsonMap);
            }
            return list;
        }
    }

    /*
     *  
     */
    public Map<String, Object> getParaToMap(String name) {
        parseJson();
        Map<String, Object> jsonMap = new HashMap<String, Object>();
        if (jsonData != null) {
            Object obj = jsonData.get(name.toLowerCase());
            if (obj instanceof JSONObject) {
                JSONObject json = (JSONObject) obj;
                for (Object k : json.keySet()) {
                    Object v = json.get(k);
                    jsonMap.put(k.toString().toLowerCase(), v);
                }
                return jsonMap;
            }
            return jsonMap;
        }
        return jsonMap;
    }

    @SuppressWarnings("rawtypes")
    public Map<String, Object> getParas() {
        parseJson();
        Map<String, Object> paras = new HashMap<String, Object>();
        if (jsonData != null) {
            for (Object k : jsonData.keySet()) {
                Object v = jsonData.get(k);
                if (v instanceof String) {
                    paras.put(k.toString().toLowerCase(), StrKit.isBlank(v.toString()) ? null : v);
                }
            }
        } else {
            Map properties = this.getRequest().getParameterMap();
            Iterator entries = properties.entrySet().iterator();
            Map.Entry entry;
            String name = "";
            String value = "";
            while (entries.hasNext()) {
                entry = (Map.Entry) entries.next();
                name = (String) entry.getKey();
                Object valueObj = entry.getValue();
                if (null == valueObj) {
                    value = "";
                } else if (valueObj instanceof String[]) {
                    String[] values = (String[]) valueObj;
                    for (int i = 0; i < values.length; i++) {
                        value = values[i] + ",";
                    }
                    value = value.substring(0, value.length() - 1);
                } else {
                    value = valueObj.toString();
                }
                paras.put(name, value);
            }
        }
        return paras;
    }

    private void parseJson() {
        if (!parseJson) {
            Enumeration<String> e = this.getRequest().getParameterNames();
            if (e.hasMoreElements()) {
                while (e.hasMoreElements()) {
                    String ename = e.nextElement();
                    if (ename.startsWith("{") || ename.startsWith("\"")) {
                        JSONObject json = JSON.parseObject(ename);
                        jsonData = new LinkedHashMap<String, Object>();
                        for (Object k : json.keySet()) {
                            Object v = json.get(k);
                            jsonData.put(k.toString().toLowerCase(), v);
                        }
                    }
                }
            }
            parseJson = true;
        }
    }

    /**
     * 获取所有request请求参数key-value
     * 
     * @param needTranscode
     *            是否需要对参数转码
     * @return Map<String, String>
     */
    protected Map<String, String> getRequestParams(boolean needTranscode) {
        Map<String, String> params = new HashMap<String, String>();
        if (null != getRequest()) {
            Set<String> paramsKey = getRequest().getParameterMap().keySet();
            for (Iterator<String> itr = paramsKey.iterator(); itr.hasNext();) {
                String paramName = itr.next();
                String valueStr = "";
                String[] values = (String[]) getRequest().getParameterValues(paramName);
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                if (needTranscode) {
                    try {
                        // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
                        valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        log.error("req param transcode failure,uri=" + getRequest().getRequestURI()
                                + ",param=" + paramName, e);
                        continue;
                    }
                }

                params.put(paramName, valueStr);
            }
        }
        return params;
    }
}
